package com.googlecode.afdbaccess.config.propertyconfig;

import java.sql.Connection;
import java.sql.SQLException;

import org.apache.commons.dbcp.DbcpException;
import org.apache.commons.dbcp.PoolingDataSource;
import org.apache.commons.pool.impl.GenericObjectPool;
import org.apache.log4j.Logger;

import com.googlecode.afdbaccess.cache.connectionpool.interfaces.ConnectionPool;

public class DBCPPool implements ConnectionPool {
  private final static Logger log = Logger.getLogger(DBCPPool.class);  
    
  private PoolingDataSource cachedDataSource;
  private GenericObjectPool connectionPool;

  public DBCPPool(PoolingDataSource poolingDataSource, GenericObjectPool connectionPool) {
    cachedDataSource = poolingDataSource;
    this.connectionPool = connectionPool;
  }

  @Override
  public Connection getConnection(String logHeader) {
    log.debug(logHeader + ": getConnection(), activeSize = " + connectionPool.getNumActive() + " idleSize = " + connectionPool.getNumIdle() + " Thread: " + Thread.currentThread());
    Connection connection = null;

    long start = System.currentTimeMillis();

    boolean needConnection = true;
    while(needConnection == true) {
      try {
        connection = cachedDataSource.getConnection();
        log.debug(logHeader + ": connection " + connection);

        needConnection = false;
      } catch(SQLException e) {
        log.debug(logHeader + ": Got a stale SQLException? Exception: " + e + " Thread: " + Thread.currentThread(), e);
        try {
          Thread.sleep(100);
        } catch (InterruptedException exception) {
          // don't care
        }
      } catch(java.util.NoSuchElementException exception) {
        // Shouldn't happen unless max wait time is set to positive number
        log.fatal(logHeader + ": Couldn't get a connection. Propably because pool reached max. activeSize = " + connectionPool.getNumActive() + " idleSize = " + connectionPool.getNumIdle() + " Thread: " + Thread.currentThread(), exception);
        try {
          Thread.sleep(1000);
        } catch (InterruptedException iexception) {
          // don't care
        }
      } catch(DbcpException exception) {
        log.fatal(logHeader + ": Couldn't get a connection. Thread: " + Thread.currentThread(), exception);
        try {
          Thread.sleep(1000);
        } catch (InterruptedException iexception) {
          // don't care
        }
      }
    }
    long end = System.currentTimeMillis();

    log.debug(logHeader + ": Got a connection. That took " + (end-start) + " ms, activeSize = " + connectionPool.getNumActive() + " idleSize = " + connectionPool.getNumIdle() + ", Thread: " + Thread.currentThread());
    return connection;
  }

  @Override
  public void yieldConnection(String logHeader, Connection conn) {
    try {
      log.debug(logHeader + ": Trying to close a connection. activeSize = " + connectionPool.getNumActive() + " idleSize = " + connectionPool.getNumIdle() + " Thread: " + Thread.currentThread());
      conn.close();
      log.debug(logHeader + ": Successfully closed a connection. activeSize = " + connectionPool.getNumActive() + " idleSize = " + connectionPool.getNumIdle() + " Thread: " + Thread.currentThread());
    } catch(SQLException e) {
      log.error(logHeader + ": Unable to close database connection. Thread: " + Thread.currentThread());
    }
  }
}